const FUN = require('../comm/func');
const rCache = require('../model/redis_cache');
const DB = require('../model/model_data');
const dbHelp = require('../comm/db-helper');
const timLib = require('../comm/time-lib');
const mbLib = require('../comm/modbus-lib');
const PMR = require('../utils/policyManger');
const dataCalc = require('../comm/data-calc');

module.exports = class Mb_Group
{
  //将数据库选项缓存到redis
  //policy 来自数据库的记录
  //opts 数据库json字段的解析对象
  //CacheCallback 存储执行函数
  static InitCache(policy,opts,CacheCallback)
  {
    let obj=PMR.baseParam(policy);//即将缓存到redis的参数

    //检查json选项
    if( parseInt(policy.record_limit)==0 ||
        parseInt(opts.fetch_period)==0 ||
        opts.wlist=='' )
    {
      console.error('wrong mb-group params',policy.id);
      return false;
    }

    //json options参数存储
    obj.fetch_period = opts.fetch_period;//采样周期
    obj.cache_expire = Number(opts.fetch_period)+60;//数据缓存reids有效期
    obj.record_limit = policy.record_limit;//数据库条数上限
    obj.record_duration = 0;//数据库周期上限
    obj.data_width = '2:n';//数据宽度
    obj.mode = opts.mode;//计算模式
    obj.wlist = opts.wlist;//寄存器白名单
    obj.res_calc = opts.calc;//结果加工表达式
    obj.excep = opts.excep?opts.excep:'';//后添数据
    obj.data_symbol = opts.data_symbol?opts.data_symbol:'false';//是否支持有符合数

    //数据库处理
    dbHelp.createTab(obj.table,policy.uid);

    //缓存主站参数
    obj.hwid = policy.master;
    obj.role = 'master';
    obj.brother = policy.brother;
    CacheCallback(policy.id,policy.master,obj);//记录到缓存

    //缓存从站参数
    if(Number(policy.brother) && policy.brother!=-1)
    {
      obj.hwid = policy.brother;
      obj.role = 'slave';
      obj.brother = policy.master;
      CacheCallback(policy.id,obj.hwid,obj);//记录到缓存
    }
  }//end InitCache


  //modbus数据总分析
  // topic = {project,devType,func,devId}
  // dConf即InitCache中的obj
  // dataBuf即mq消息内容，buf对象
  static async DataIn(topic, dConf, dataBuf)
  {
    mbLib.mbPacketParse(topic.func, dConf, dataBuf, (last,sConf)=>{
      this.dataHandler(last,sConf,dataBuf,timLib.NowStamp());
    })
  }//end function DataIn

  //检查是否在白名单中
  static checkWlist(addr,reg,rA,rS,rE)
  {
    for(let i in rA) if(addr==rA[i] && reg>=rS[i] && reg<rE[i]) return true;
    return false;
  }

  //普通的数据处理,每隔一段时间就求平均值入数据库
  static dataHandler(last,dConf,data,stamp)
  {
    let nodeDevStamp=PMR.rdNode(dConf)+':'+timLib.Rounding(dConf.fetch_period,stamp);
    let nodeDevAddr=nodeDevStamp+':'+last.addr;

    //处理前一个数据，为提高效率，此处不能用await
    //第一条报文来的时候，会将上一时段所有报文都处理
    rCache.get(nodeDevStamp,'addrs',last.addr).then((val)=>{
      if(val!=last.addr) //不存在,说明现在是第一个数据,那么可以处理旧数据
      {
        dataCalc.prevDataCalc(PMR.rdNode(dConf),dConf,dConf.mode,(mode,fields,dArray)=>{
          let needInform=false;
          if(dConf.table.includes('dat_json') && mode=='reg-json'){DB.newRcd(dConf.uid,dConf.table,fields,dArray);needInform=true;}
          if(needInform) PMR.policyInform('update',dConf);//通知前端
        })
      }
    })

    //计数，报文次数，包含多条不同报文计数，做平均值时无法使用
    rCache.incKey(nodeDevAddr,'count',dConf.cache_expire);

    //记地址
    let obj={};
    obj[last.addr]=last.addr;
    rCache.set(nodeDevStamp,'addrs',obj,dConf.cache_expire);

    //处理白名单
    let wlist=dConf.wlist.split(",");
    let rAddrs=[];
    let rStarts=[];
    let rEnds=[];

    for(let alist of wlist)
    {
      alist=alist.split(':');
      if(alist.length!=2 || alist[0][0]!='#') continue;
      let reg_i=alist[1].split('-');
      if(reg_i.length!=2) continue;

      let myAddr=parseInt(alist[0].substr(1));
      let myStart=parseInt(reg_i[0]);
      let myNum=parseInt(reg_i[1]);
      if(isNaN(myAddr) || isNaN(myStart) || isNaN(myNum)) continue;

      rAddrs.push(myAddr);
      rStarts.push(myStart);
      rEnds.push(myStart+myNum);
    }//end for alist

    //记数值
    let data_fmt=dConf.data_width.split(':');//分割数据宽度和数据格式
    for(let i=0;i<last.regNum;i+=(data_fmt[0]/2))
    {
      let reg=Number(last.regStart)+i;
      if(this.checkWlist(last.addr,reg,rAddrs,rStarts,rEnds))//白名单过滤
      {
        let regVal=(Number(data[3+i*2])<<8)+Number(data[4+i*2]);
        if (dConf.data_symbol == 'true' && regVal >= 0x8000) {
          regVal = 0 - (0x10000 - regVal);
        }

        if(data_fmt[0]==4)//不同字节长度得的处理
          regVal=(regVal<<16)+(Number(data[5+i*2])<<8)+Number(data[6+i*2]);

        if(data_fmt[1]=='f') regVal=FUN.ieee745_toFloat(regVal).toFixed(4);
        rCache.push(nodeDevAddr,'reg.'+reg,regVal,dConf.cache_expire);//存储到缓存
      }
    }
  }//end funciton

} //end class Modbus